/**
  ******************************************************************************
  * @file    usart.c
  * @brief   This file provides code for the configuration
  *          of the USART instances.
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "bsp.h"
#include <stdio.h>

//#define TTY_RECVCMD_ENABLE

#define TTY_UART_TX_Pin              GPIO_PIN_7
#define TTY_UART_TX_LL_Pin           LL_GPIO_PIN_7
#define TTY_UART_TX_LL_Pin_AF        LL_GPIO_AF_8
#define TTY_UART_TX_GPIO_Port        GPIOG

#define TTY_UART_RX_Pin              GPIO_PIN_8
#define TTY_UART_RX_LL_Pin           LL_GPIO_PIN_8
#define TTY_UART_RX_LL_Pin_AF        LL_GPIO_AF_8
#define TTY_UART_RX_GPIO_Port        GPIOG

#define TTY_UART                     LPUART1
#define TTY_UART_IRQn                LPUART1_IRQn
#define TTY_UART_IRQHandler          LPUART1_IRQHandler
#define TTY_UART_RCC_EnableClock()   LL_RCC_SetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_PCLK1)
#define TTY_UART_EnableClock()       LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPUART1)
#define TTY_UART_IO_EnableClock()    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOG)


void SystemUSART_Config(void)
{
  LL_LPUART_InitTypeDef LPUART_InitStruct = {0};
  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

  TTY_UART_RCC_EnableClock();
  TTY_UART_EnableClock();
  TTY_UART_IO_EnableClock();
  
  LL_PWR_EnableVddIO2();
  
  GPIO_InitStruct.Pin = TTY_UART_TX_LL_Pin;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
  GPIO_InitStruct.Alternate = TTY_UART_TX_LL_Pin_AF;
  LL_GPIO_Init(TTY_UART_TX_GPIO_Port, &GPIO_InitStruct);

  GPIO_InitStruct.Pin = TTY_UART_RX_LL_Pin;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
  GPIO_InitStruct.Alternate = TTY_UART_RX_LL_Pin_AF;
  LL_GPIO_Init(TTY_UART_RX_GPIO_Port, &GPIO_InitStruct);


  LPUART_InitStruct.BaudRate = 115200;
  LPUART_InitStruct.DataWidth = LL_LPUART_DATAWIDTH_8B;
  LPUART_InitStruct.StopBits = LL_LPUART_STOPBITS_1;
  LPUART_InitStruct.Parity = LL_LPUART_PARITY_NONE;
#ifdef TTY_RECVCMD_ENABLE
  USART_InitStruct.TransferDirection = LL_LPUART_DIRECTION_TX_RX;
#else
  LPUART_InitStruct.TransferDirection = LL_LPUART_DIRECTION_TX;
#endif
  LPUART_InitStruct.HardwareFlowControl = LL_LPUART_HWCONTROL_NONE;
  LL_LPUART_Init(TTY_UART, &LPUART_InitStruct);
  
  
#if defined(USART_CR1_FIFOEN)  
  LL_LPUART_SetTXFIFOThreshold(TTY_UART, LL_LPUART_FIFOTHRESHOLD_1_8);
  LL_LPUART_SetRXFIFOThreshold(TTY_UART, LL_LPUART_FIFOTHRESHOLD_1_8);
  LL_LPUART_DisableFIFO(TTY_UART);
#endif

  LL_LPUART_SetDEAssertionTime(TTY_UART, 31);                      /* 485方向控制脚的时间 */
  LL_LPUART_SetDEDeassertionTime(TTY_UART, 31);                    /* 485方向控制脚的时间 */
  LL_LPUART_SetDESignalPolarity(TTY_UART, LL_LPUART_DE_POLARITY_HIGH);
  LL_LPUART_DisableDEMode(TTY_UART);
  
  LL_LPUART_DisableDMADeactOnRxErr(TTY_UART);
  
  LL_LPUART_DisableInStopMode(TTY_UART);                           /* 低功耗模式下唤醒mcu: disable */
  
	LL_LPUART_SetWakeUpMethod(TTY_UART, LL_LPUART_WAKEUP_IDLELINE);   /* uart唤醒方法:空闲线路和地址匹配 */
  LL_LPUART_DisableMuteMode(TTY_UART);                             /* 关闭uart唤醒功能,始终处于工作模式,若为唤醒模式,则根据上面的唤醒方法 */
  
  LL_LPUART_SetTXRXSwap(TTY_UART, LL_LPUART_TXRX_STANDARD);         /* tx rx引脚交换:标准 */
  
  LL_LPUART_SetTXPinLevel(TTY_UART, LL_LPUART_TXPIN_LEVEL_STANDARD);
  LL_LPUART_SetRXPinLevel(TTY_UART, LL_LPUART_RXPIN_LEVEL_STANDARD);
  LL_LPUART_SetBinaryDataLogic(TTY_UART, LL_LPUART_BINARY_LOGIC_POSITIVE);
  
  LL_LPUART_DisableHalfDuplex(TTY_UART);

#ifdef TTY_RECVCMD_ENABLE
  NVIC_SetPriority(TTY_UART_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), TTY_UART_IRQn_PRIORITY, 0));
  NVIC_EnableIRQ(TTY_UART_IRQn);
  
  LL_LPUART_EnableIT_RXNE(TTY_UART);
#else
	LL_LPUART_DisableIT_RXNE(TTY_UART);
#endif

  LL_LPUART_Enable(TTY_UART);

  /* Polling TTY_UART initialisation */
  while(!(LL_LPUART_IsActiveFlag_TEACK(TTY_UART)))
  {
  }
  
#ifdef TTY_RECVCMD_ENABLE  
  while(!(LL_LPUART_IsActiveFlag_REACK(TTY_UART)))
  {
  }
#endif
}

void Tty_Sendbuf(const uint8_t *buf, uint32_t len)
{
	uint32_t i;
	
	for(i=0; i<len; i++)
	{
    TTY_UART->TDR = (buf[i]& (uint16_t)0x01FFU);
    while(READ_BIT(TTY_UART->ISR, USART_ISR_TXE) != (USART_ISR_TXE));
	}
	
	while(READ_BIT(TTY_UART->ISR, USART_ISR_TC) != (USART_ISR_TC));
}

#ifdef TTY_RECVCMD_ENABLE
extern void Terminal_RecvIsr(uint8_t dat);
extern void Terminal_BreakIsr(void);
#endif

void TTY_UART_IRQHandler(void)
{
	if(READ_BIT(TTY_UART->ISR, USART_ISR_RXNE) != 0)
	{
#ifdef TTY_RECVCMD_ENABLE
		Terminal_RecvIsr(TTY_UART->RDR);
#endif
	}
  
  if(READ_BIT(TTY_UART->ISR, USART_ISR_ORE) != 0)
	{
    LL_LPUART_ClearFlag_ORE(TTY_UART);
  }
}

FILE __stdout;

int fputc(int ch, FILE *f)
{
  TTY_UART->TDR = ( (uint8_t)ch & (uint16_t)0x01FF );
  while(READ_BIT(TTY_UART->ISR, USART_ISR_TXE) != (USART_ISR_TXE));

  return (ch);
}
